
            <!DOCTYPE html>
            <html lang="en">
            <head>
                <meta charset="UTF-8">
                <title>[k8s] 第八章 数据存储</title>
            </head>
            <body>
            <a href="https://andyoung.blog.csdn.net">原作者博客</a>
            <div id="content_views" class="markdown_views prism-atom-one-light">
                    <svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
                        <path stroke-linecap="round" d="M5,0 0,2.5 5,5z" id="raphael-marker-block" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></path>
                    </svg>
                    <p>​ 在前面已经提到，容器的生命周期可能很短，会被频繁地创建和销毁。那么容器在销毁时，保存在容器中的数据也会被清除。这种结果对用户来说，在某些情况下是不乐意看到的。为了持久化保存容器的数据，kubernetes引入了Volume的概念。</p> 
<p>​ Volume是Pod中能够被多个容器访问的共享目录，它被定义在Pod上，然后被一个Pod里的多个容器挂载到具体的文件目录下，kubernetes通过Volume实现同一个Pod中不同容器之间的数据共享以及数据的持久化存储。Volume的生命容器不与Pod中单个容器的生命周期相关，当容器终止或者重启时，Volume中的数据也不会丢失。</p> 
<p>kubernetes的Volume支持多种类型，比较常见的有下面几个：</p> 
<ul><li>简单存储：EmptyDir、HostPath、NFS</li><li>高级存储：PV、PVC</li><li>配置存储：ConfigMap、Secret</li></ul> 
<h3><a id="_12"></a>基本存储</h3> 
<h4><a id="EmptyDir_14"></a>EmptyDir</h4> 
<p>​ EmptyDir是最基础的Volume类型，一个EmptyDir就是Host上的一个空目录。</p> 
<p>​ EmptyDir是在Pod被分配到Node时创建的，它的初始内容为空，并且无须指定宿主机上对应的目录文件，因为kubernetes会自动分配一个目录，当Pod销毁时， EmptyDir中的数据也会被永久删除。 EmptyDir用途如下：</p> 
<ul><li> <p>临时空间，例如用于某些应用程序运行时所需的临时目录，且无须永久保留</p> </li><li> <p>一个容器需要从另一个容器中获取数据的目录（多容器共享目录）</p> </li></ul> 
<p>接下来，通过一个容器之间文件共享的案例来使用一下EmptyDir。</p> 
<p>​ 在一个Pod中准备两个容器nginx和busybox，然后声明一个Volume分别挂在到两个容器的目录中，然后nginx容器负责向Volume中写日志，busybox中通过命令将日志内容读到控制台。</p> 
<p><img src="https://i-blog.csdnimg.cn/blog_migrate/17cfd4e735b194cb1aeb0a4852933e6a.png" alt=""></p> 
<p>创建一个volume-emptydir.yaml</p> 
<pre><code class="prism language-yaml"><span class="token key atrule">apiVersion</span><span class="token punctuation">:</span> v1
<span class="token key atrule">kind</span><span class="token punctuation">:</span> Pod
<span class="token key atrule">metadata</span><span class="token punctuation">:</span>
  <span class="token key atrule">name</span><span class="token punctuation">:</span> volume<span class="token punctuation">-</span>emptydir
  <span class="token key atrule">namespace</span><span class="token punctuation">:</span> dev
<span class="token key atrule">spec</span><span class="token punctuation">:</span>
  <span class="token key atrule">containers</span><span class="token punctuation">:</span>
  <span class="token punctuation">-</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> nginx
    <span class="token key atrule">image</span><span class="token punctuation">:</span> nginx<span class="token punctuation">:</span>1.14<span class="token punctuation">-</span>alpine
    <span class="token key atrule">ports</span><span class="token punctuation">:</span>
    <span class="token punctuation">-</span> <span class="token key atrule">containerPort</span><span class="token punctuation">:</span> <span class="token number">80</span>
    <span class="token key atrule">volumeMounts</span><span class="token punctuation">:</span>  <span class="token comment"># 将logs-volume挂在到nginx容器中，对应的目录为 /var/log/nginx</span>
    <span class="token punctuation">-</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> logs<span class="token punctuation">-</span>volume
      <span class="token key atrule">mountPath</span><span class="token punctuation">:</span> /var/log/nginx
  <span class="token punctuation">-</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> busybox
    <span class="token key atrule">image</span><span class="token punctuation">:</span> busybox<span class="token punctuation">:</span><span class="token number">1.30</span>
    <span class="token key atrule">command</span><span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">"/bin/sh"</span><span class="token punctuation">,</span><span class="token string">"-c"</span><span class="token punctuation">,</span><span class="token string">"tail -f /logs/access.log"</span><span class="token punctuation">]</span> <span class="token comment"># 初始命令，动态读取指定文件中内容</span>
    <span class="token key atrule">volumeMounts</span><span class="token punctuation">:</span>  <span class="token comment"># 将logs-volume 挂在到busybox容器中，对应的目录为 /logs</span>
    <span class="token punctuation">-</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> logs<span class="token punctuation">-</span>volume
      <span class="token key atrule">mountPath</span><span class="token punctuation">:</span> /logs
  <span class="token key atrule">volumes</span><span class="token punctuation">:</span> <span class="token comment"># 声明volume， name为logs-volume，类型为emptyDir</span>
  <span class="token punctuation">-</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> logs<span class="token punctuation">-</span>volume
    <span class="token key atrule">emptyDir</span><span class="token punctuation">:</span> <span class="token punctuation">{<!-- --></span><span class="token punctuation">}</span>
</code></pre> 
<pre><code class="prism language-powershell"><span class="token comment"># 创建Pod</span>
<span class="token namespace">[root@master ~]</span><span class="token comment"># kubectl create -f volume-emptydir.yaml</span>
pod/volume-emptydir created

<span class="token comment"># 查看pod</span>
<span class="token namespace">[root@master ~]</span><span class="token comment"># kubectl get pods volume-emptydir -n dev -o wide</span>
NAME                  READY   STATUS    RESTARTS   AGE   IP             NODE   <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span> 
volume-emptydir   2/2     Running   0          97s   10<span class="token punctuation">.</span>244<span class="token punctuation">.</span>1<span class="token punctuation">.</span>100   node1  <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>

<span class="token comment"># 通过podIp访问nginx</span>
<span class="token namespace">[root@master ~]</span><span class="token comment"># curl 10.244.1.100</span>
<span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>

<span class="token comment"># 通过kubectl logs命令查看指定容器的标准输出</span>
<span class="token namespace">[root@master ~]</span><span class="token comment"># kubectl logs -f volume-emptydir -n dev -c busybox</span>
10<span class="token punctuation">.</span>244<span class="token punctuation">.</span>0<span class="token punctuation">.</span>0 <span class="token operator">-</span> <span class="token operator">-</span> <span class="token punctuation">[</span>13/Apr/2020:10:58:47 <span class="token operator">+</span>0000<span class="token punctuation">]</span> <span class="token string">"GET / HTTP/1.1"</span> 200 612 <span class="token string">"-"</span> <span class="token string">"curl/7.29.0"</span> <span class="token string">"-"</span>
</code></pre> 
<h4><a id="HostPath_77"></a>HostPath</h4> 
<p>​ 上节课提到，EmptyDir中数据不会被持久化，它会随着Pod的结束而销毁，如果想简单的将数据持久化到主机中，可以选择HostPath。</p> 
<p>​ HostPath就是将Node主机中一个实际目录挂在到Pod中，以供容器使用，这样的设计就可以保证Pod销毁了，但是数据依据可以存在于Node主机上。</p> 
<p><img src="https://i-blog.csdnimg.cn/blog_migrate/63bfe22f861bcd4eefd8640dc8079030.png" alt=""></p> 
<p>创建一个volume-hostpath.yaml：</p> 
<pre><code class="prism language-yaml"><span class="token key atrule">apiVersion</span><span class="token punctuation">:</span> v1
<span class="token key atrule">kind</span><span class="token punctuation">:</span> Pod
<span class="token key atrule">metadata</span><span class="token punctuation">:</span>
  <span class="token key atrule">name</span><span class="token punctuation">:</span> volume<span class="token punctuation">-</span>hostpath
  <span class="token key atrule">namespace</span><span class="token punctuation">:</span> dev
<span class="token key atrule">spec</span><span class="token punctuation">:</span>
  <span class="token key atrule">containers</span><span class="token punctuation">:</span>
  <span class="token punctuation">-</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> nginx
    <span class="token key atrule">image</span><span class="token punctuation">:</span> nginx<span class="token punctuation">:</span>1.17.1
    <span class="token key atrule">ports</span><span class="token punctuation">:</span>
    <span class="token punctuation">-</span> <span class="token key atrule">containerPort</span><span class="token punctuation">:</span> <span class="token number">80</span>
    <span class="token key atrule">volumeMounts</span><span class="token punctuation">:</span>
    <span class="token punctuation">-</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> logs<span class="token punctuation">-</span>volume
      <span class="token key atrule">mountPath</span><span class="token punctuation">:</span> /var/log/nginx
  <span class="token punctuation">-</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> busybox
    <span class="token key atrule">image</span><span class="token punctuation">:</span> busybox<span class="token punctuation">:</span><span class="token number">1.30</span>
    <span class="token key atrule">command</span><span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">"/bin/sh"</span><span class="token punctuation">,</span><span class="token string">"-c"</span><span class="token punctuation">,</span><span class="token string">"tail -f /logs/access.log"</span><span class="token punctuation">]</span>
    <span class="token key atrule">volumeMounts</span><span class="token punctuation">:</span>
    <span class="token punctuation">-</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> logs<span class="token punctuation">-</span>volume
      <span class="token key atrule">mountPath</span><span class="token punctuation">:</span> /logs
  <span class="token key atrule">volumes</span><span class="token punctuation">:</span>
  <span class="token punctuation">-</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> logs<span class="token punctuation">-</span>volume
    <span class="token key atrule">hostPath</span><span class="token punctuation">:</span> 
      <span class="token key atrule">path</span><span class="token punctuation">:</span> /root/logs
      <span class="token key atrule">type</span><span class="token punctuation">:</span> DirectoryOrCreate  <span class="token comment"># 目录存在就使用，不存在就先创建后使用</span>
</code></pre> 
<pre><code class="prism language-markdown">关于type的值的一点说明：
	DirectoryOrCreate 目录存在就使用，不存在就先创建后使用
	Directory	目录必须存在
	FileOrCreate  文件存在就使用，不存在就先创建后使用
	File 文件必须存在	
    Socket	unix套接字必须存在
	CharDevice	字符设备必须存在
	BlockDevice 块设备必须存在
</code></pre> 
<pre><code class="prism language-powershell"><span class="token comment"># 创建Pod</span>
<span class="token namespace">[root@master ~]</span><span class="token comment"># kubectl create -f volume-hostpath.yaml</span>
pod/volume-hostpath created

<span class="token comment"># 查看Pod</span>
<span class="token namespace">[root@master ~]</span><span class="token comment"># kubectl get pods volume-hostpath -n dev -o wide</span>
NAME                  READY   STATUS    RESTARTS   AGE   IP             NODE   <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
pod-volume-hostpath   2/2     Running   0          16s   10<span class="token punctuation">.</span>244<span class="token punctuation">.</span>1<span class="token punctuation">.</span>104   node1  <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>

<span class="token comment">#访问nginx</span>
<span class="token namespace">[root@master ~]</span><span class="token comment"># curl 10.244.1.104</span>

<span class="token comment"># 接下来就可以去host的/root/logs目录下查看存储的文件了</span>
<span class="token comment">###  注意: 下面的操作需要到Pod所在的节点运行（案例中是node1）</span>
<span class="token namespace">[root@node1 ~]</span><span class="token comment"># ls /root/logs/</span>
access<span class="token punctuation">.</span>log  error<span class="token punctuation">.</span>log

<span class="token comment"># 同样的道理，如果在此目录下创建一个文件，到容器中也是可以看到的</span>
</code></pre> 
<h4><a id="NFS_147"></a>NFS</h4> 
<p>​ HostPath可以解决数据持久化的问题，但是一旦Node节点故障了，Pod如果转移到了别的节点，又会出现问题了，此时需要准备单独的网络存储系统，比较常用的用NFS、CIFS。</p> 
<p>​ NFS是一个网络文件存储系统，可以搭建一台NFS服务器，然后将Pod中的存储直接连接到NFS系统上，这样的话，无论Pod在节点上怎么转移，只要Node跟NFS的对接没问题，数据就可以成功访问。</p> 
<p><img src="https://i-blog.csdnimg.cn/blog_migrate/47c073f4b0ae87ec996dc4aac7179c41.png" alt=""></p> 
<p>1）首先要准备nfs的服务器，这里为了简单，直接是master节点做nfs服务器</p> 
<pre><code class="prism language-powershell"><span class="token comment"># 在master上安装nfs服务</span>
<span class="token namespace">[root@master ~]</span><span class="token comment"># yum install nfs-utils -y</span>

<span class="token comment"># 准备一个共享目录</span>
<span class="token namespace">[root@master ~]</span><span class="token comment"># mkdir /root/data/nfs -pv</span>

<span class="token comment"># 将共享目录以读写权限暴露给192.168.109.0/24网段中的所有主机</span>
<span class="token namespace">[root@master ~]</span><span class="token comment"># vim /etc/exports</span>
<span class="token namespace">[root@master ~]</span><span class="token comment"># more /etc/exports</span>
<span class="token operator">/</span>root/<span class="token keyword">data</span><span class="token operator">/</span>nfs     192<span class="token punctuation">.</span>168<span class="token punctuation">.</span>109<span class="token punctuation">.</span>0/24<span class="token punctuation">(</span>rw<span class="token punctuation">,</span>no_root_squash<span class="token punctuation">)</span>

<span class="token comment"># 启动nfs服务</span>
<span class="token namespace">[root@master ~]</span><span class="token comment"># systemctl start nfs</span>
</code></pre> 
<p>配置说明：</p> 
<p>/root/data/nfs：是共享的数据目录<br> 192.168.109.0/24：这个网段里的可以访问。<code>*</code>表示任何人都有权限连接，当然也可以是一个网段，一个 IP，也可以是域名<br> rw：读写的权限<br> sync：表示文件同时写入硬盘和内存<br> no_root_squash：当登录 NFS 主机使用共享目录的使用者是 root 时，其权限将被转换成为匿名使用者，通常它的 UID 与 GID，都会变成 nobody 身份</p> 
<p>2）接下来，要在的每个node节点上都安装下nfs，这样的目的是为了node节点可以驱动nfs设备</p> 
<pre><code class="prism language-powershell"><span class="token comment"># 在node上安装nfs服务，注意不需要启动</span>
<span class="token namespace">[root@master ~]</span><span class="token comment"># yum install nfs-utils -y</span>
</code></pre> 
<p>3）接下来，就可以编写pod的配置文件了，创建volume-nfs.yaml</p> 
<pre><code class="prism language-yaml"><span class="token key atrule">apiVersion</span><span class="token punctuation">:</span> v1
<span class="token key atrule">kind</span><span class="token punctuation">:</span> Pod
<span class="token key atrule">metadata</span><span class="token punctuation">:</span>
  <span class="token key atrule">name</span><span class="token punctuation">:</span> volume<span class="token punctuation">-</span>nfs
  <span class="token key atrule">namespace</span><span class="token punctuation">:</span> dev
<span class="token key atrule">spec</span><span class="token punctuation">:</span>
  <span class="token key atrule">containers</span><span class="token punctuation">:</span>
  <span class="token punctuation">-</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> nginx
    <span class="token key atrule">image</span><span class="token punctuation">:</span> nginx<span class="token punctuation">:</span>1.17.1
    <span class="token key atrule">ports</span><span class="token punctuation">:</span>
    <span class="token punctuation">-</span> <span class="token key atrule">containerPort</span><span class="token punctuation">:</span> <span class="token number">80</span>
    <span class="token key atrule">volumeMounts</span><span class="token punctuation">:</span>
    <span class="token punctuation">-</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> logs<span class="token punctuation">-</span>volume
      <span class="token key atrule">mountPath</span><span class="token punctuation">:</span> /var/log/nginx
  <span class="token punctuation">-</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> busybox
    <span class="token key atrule">image</span><span class="token punctuation">:</span> busybox<span class="token punctuation">:</span><span class="token number">1.30</span>
    <span class="token key atrule">command</span><span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">"/bin/sh"</span><span class="token punctuation">,</span><span class="token string">"-c"</span><span class="token punctuation">,</span><span class="token string">"tail -f /logs/access.log"</span><span class="token punctuation">]</span> 
    <span class="token key atrule">volumeMounts</span><span class="token punctuation">:</span>
    <span class="token punctuation">-</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> logs<span class="token punctuation">-</span>volume
      <span class="token key atrule">mountPath</span><span class="token punctuation">:</span> /logs
  <span class="token key atrule">volumes</span><span class="token punctuation">:</span>
  <span class="token punctuation">-</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> logs<span class="token punctuation">-</span>volume
    <span class="token key atrule">nfs</span><span class="token punctuation">:</span>
      <span class="token key atrule">server</span><span class="token punctuation">:</span> 192.168.109.100  <span class="token comment">#nfs服务器地址</span>
      <span class="token key atrule">path</span><span class="token punctuation">:</span> /root/data/nfs <span class="token comment">#共享文件路径</span>
</code></pre> 
<p>4）最后，运行下pod，观察结果</p> 
<pre><code class="prism language-powershell"><span class="token comment"># 创建pod</span>
<span class="token namespace">[root@master ~]</span><span class="token comment"># kubectl create -f volume-nfs.yaml</span>
pod/volume-nfs created

<span class="token comment"># 查看pod</span>
<span class="token namespace">[root@master ~]</span><span class="token comment"># kubectl get pods volume-nfs -n dev</span>
NAME                  READY   STATUS    RESTARTS   AGE
volume-nfs        2/2     Running   0          2m9s

<span class="token comment"># 查看nfs服务器上的共享目录，发现已经有文件了</span>
<span class="token namespace">[root@master ~]</span><span class="token comment"># ls /root/data/</span>
access<span class="token punctuation">.</span>log  error<span class="token punctuation">.</span>log
</code></pre> 
<h3><a id="_234"></a>高级存储</h3> 
<h4><a id="PVPVC_236"></a>PV和PVC</h4> 
<p>​ 前面已经学习了使用NFS提供存储，此时就要求用户会搭建NFS系统，并且会在yaml配置nfs。由于kubernetes支持的存储系统有很多，要求客户全都掌握，显然不现实。为了能够屏蔽底层存储实现的细节，方便用户使用， kubernetes引入PV和PVC两种资源对象。</p> 
<p>​ PV（Persistent Volume）是持久化卷的意思，是对底层的共享存储的一种抽象。一般情况下PV由kubernetes管理员进行创建和配置，它与底层具体的共享存储技术有关，并通过插件完成与共享存储的对接。</p> 
<p>​ PVC（Persistent Volume Claim）是持久卷声明的意思，是用户对于存储需求的一种声明。换句话说，PVC其实就是用户向kubernetes系统发出的一种资源需求申请。</p> 
<p><img src="https://i-blog.csdnimg.cn/blog_migrate/e94791696b7b74a4cdcfa69475462f6e.png" alt=""></p> 
<p>使用了PV和PVC之后，工作可以得到进一步的细分：</p> 
<ul><li>存储：存储工程师维护</li><li>PV： kubernetes管理员维护</li><li>PVC：kubernetes用户维护</li></ul> 
<h4><a id="PV_252"></a>PV</h4> 
<p>PV是存储资源的抽象，下面是资源清单文件:</p> 
<pre><code class="prism language-yaml"><span class="token key atrule">apiVersion</span><span class="token punctuation">:</span> v1  
<span class="token key atrule">kind</span><span class="token punctuation">:</span> PersistentVolume
<span class="token key atrule">metadata</span><span class="token punctuation">:</span>
  <span class="token key atrule">name</span><span class="token punctuation">:</span> pv2
<span class="token key atrule">spec</span><span class="token punctuation">:</span>
  <span class="token key atrule">nfs</span><span class="token punctuation">:</span> <span class="token comment"># 存储类型，与底层真正存储对应</span>
  <span class="token key atrule">capacity</span><span class="token punctuation">:</span>  <span class="token comment"># 存储能力，目前只支持存储空间的设置</span>
    <span class="token key atrule">storage</span><span class="token punctuation">:</span> 2Gi
  <span class="token key atrule">accessModes</span><span class="token punctuation">:</span>  <span class="token comment"># 访问模式</span>
  <span class="token key atrule">storageClassName</span><span class="token punctuation">:</span> <span class="token comment"># 存储类别</span>
  <span class="token key atrule">persistentVolumeReclaimPolicy</span><span class="token punctuation">:</span> <span class="token comment"># 回收策略</span>
</code></pre> 
<p>PV 的关键配置参数说明：</p> 
<ul><li> <p><strong>存储类型</strong></p> <p>底层实际存储的类型，kubernetes支持多种存储类型，每种存储类型的配置都有所差异</p> </li><li> <p><strong>存储能力（capacity）</strong></p> </li></ul> 
<p>​ 目前只支持存储空间的设置( storage=1Gi )，不过未来可能会加入IOPS、吞吐量等指标的配置</p> 
<ul><li> <p><strong>访问模式（accessModes）</strong></p> <p>用于描述用户应用对存储资源的访问权限，访问权限包括下面几种方式：</p> 
  <ul><li>ReadWriteOnce（RWO）：读写权限，但是只能被单个节点挂载</li><li>ReadOnlyMany（ROX）： 只读权限，可以被多个节点挂载</li><li>ReadWriteMany（RWX）：读写权限，可以被多个节点挂载</li></ul> <p><code>需要注意的是，底层不同的存储类型可能支持的访问模式不同</code></p> </li><li> <p><strong>回收策略（persistentVolumeReclaimPolicy）</strong></p> <p>当PV不再被使用了之后，对其的处理方式。目前支持三种策略：</p> 
  <ul><li>Retain （保留） 保留数据，需要管理员手工清理数据</li><li>Recycle（回收） 清除 PV 中的数据，效果相当于执行 rm -rf /thevolume/*</li><li>Delete （删除） 与 PV 相连的后端存储完成 volume 的删除操作，当然这常见于云服务商的存储服务</li></ul> <p><code>需要注意的是，底层不同的存储类型可能支持的回收策略不同</code></p> </li><li> <p><strong>存储类别</strong></p> <p>PV可以通过storageClassName参数指定一个存储类别</p> 
  <ul><li> <p>具有特定类别的PV只能与请求了该类别的PVC进行绑定</p> </li><li> <p>未设定类别的PV则只能与不请求任何类别的PVC进行绑定</p> </li></ul> </li><li> <p><strong>状态（status）</strong></p> <p>一个 PV 的生命周期中，可能会处于4中不同的阶段：</p> 
  <ul><li>Available（可用）： 表示可用状态，还未被任何 PVC 绑定</li><li>Bound（已绑定）： 表示 PV 已经被 PVC 绑定</li><li>Released（已释放）： 表示 PVC 被删除，但是资源还未被集群重新声明</li><li>Failed（失败）： 表示该 PV 的自动回收失败</li></ul> </li></ul> 
<p><strong>实验</strong></p> 
<p>使用NFS作为存储，来演示PV的使用，创建3个PV，对应NFS中的3个暴露的路径。</p> 
<ol><li>准备NFS环境</li></ol> 
<pre><code class="prism language-powershell"><span class="token comment"># 创建目录</span>
<span class="token namespace">[root@master ~]</span><span class="token comment"># mkdir /root/data/{pv1,pv2,pv3} -pv</span>

<span class="token comment"># 暴露服务</span>
<span class="token namespace">[root@master ~]</span><span class="token comment"># more /etc/exports</span>
<span class="token operator">/</span>root/<span class="token keyword">data</span><span class="token operator">/</span>pv1     192<span class="token punctuation">.</span>168<span class="token punctuation">.</span>109<span class="token punctuation">.</span>0/24<span class="token punctuation">(</span>rw<span class="token punctuation">,</span>no_root_squash<span class="token punctuation">)</span>
<span class="token operator">/</span>root/<span class="token keyword">data</span><span class="token operator">/</span>pv2     192<span class="token punctuation">.</span>168<span class="token punctuation">.</span>109<span class="token punctuation">.</span>0/24<span class="token punctuation">(</span>rw<span class="token punctuation">,</span>no_root_squash<span class="token punctuation">)</span>
<span class="token operator">/</span>root/<span class="token keyword">data</span><span class="token operator">/</span>pv3     192<span class="token punctuation">.</span>168<span class="token punctuation">.</span>109<span class="token punctuation">.</span>0/24<span class="token punctuation">(</span>rw<span class="token punctuation">,</span>no_root_squash<span class="token punctuation">)</span>

<span class="token comment"># 重启服务</span>
<span class="token namespace">[root@master ~]</span><span class="token comment">#  systemctl restart nfs</span>
</code></pre> 
<ol start="2"><li>创建pv.yaml</li></ol> 
<pre><code class="prism language-yaml"><span class="token key atrule">apiVersion</span><span class="token punctuation">:</span> v1
<span class="token key atrule">kind</span><span class="token punctuation">:</span> PersistentVolume
<span class="token key atrule">metadata</span><span class="token punctuation">:</span>
  <span class="token key atrule">name</span><span class="token punctuation">:</span>  pv1
<span class="token key atrule">spec</span><span class="token punctuation">:</span>
  <span class="token key atrule">capacity</span><span class="token punctuation">:</span> 
    <span class="token key atrule">storage</span><span class="token punctuation">:</span> 1Gi
  <span class="token key atrule">accessModes</span><span class="token punctuation">:</span>
  <span class="token punctuation">-</span> ReadWriteMany
  <span class="token key atrule">persistentVolumeReclaimPolicy</span><span class="token punctuation">:</span> Retain
  <span class="token key atrule">nfs</span><span class="token punctuation">:</span>
    <span class="token key atrule">path</span><span class="token punctuation">:</span> /root/data/pv1
    <span class="token key atrule">server</span><span class="token punctuation">:</span> 192.168.109.100

<span class="token punctuation">---</span>

<span class="token key atrule">apiVersion</span><span class="token punctuation">:</span> v1
<span class="token key atrule">kind</span><span class="token punctuation">:</span> PersistentVolume
<span class="token key atrule">metadata</span><span class="token punctuation">:</span>
  <span class="token key atrule">name</span><span class="token punctuation">:</span>  pv2
<span class="token key atrule">spec</span><span class="token punctuation">:</span>
  <span class="token key atrule">capacity</span><span class="token punctuation">:</span> 
    <span class="token key atrule">storage</span><span class="token punctuation">:</span> 2Gi
  <span class="token key atrule">accessModes</span><span class="token punctuation">:</span>
  <span class="token punctuation">-</span> ReadWriteMany
  <span class="token key atrule">persistentVolumeReclaimPolicy</span><span class="token punctuation">:</span> Retain
  <span class="token key atrule">nfs</span><span class="token punctuation">:</span>
    <span class="token key atrule">path</span><span class="token punctuation">:</span> /root/data/pv2
    <span class="token key atrule">server</span><span class="token punctuation">:</span> 192.168.109.100
    
<span class="token punctuation">---</span>

<span class="token key atrule">apiVersion</span><span class="token punctuation">:</span> v1
<span class="token key atrule">kind</span><span class="token punctuation">:</span> PersistentVolume
<span class="token key atrule">metadata</span><span class="token punctuation">:</span>
  <span class="token key atrule">name</span><span class="token punctuation">:</span>  pv3
<span class="token key atrule">spec</span><span class="token punctuation">:</span>
  <span class="token key atrule">capacity</span><span class="token punctuation">:</span> 
    <span class="token key atrule">storage</span><span class="token punctuation">:</span> 3Gi
  <span class="token key atrule">accessModes</span><span class="token punctuation">:</span>
  <span class="token punctuation">-</span> ReadWriteMany
  <span class="token key atrule">persistentVolumeReclaimPolicy</span><span class="token punctuation">:</span> Retain
  <span class="token key atrule">nfs</span><span class="token punctuation">:</span>
    <span class="token key atrule">path</span><span class="token punctuation">:</span> /root/data/pv3
    <span class="token key atrule">server</span><span class="token punctuation">:</span> 192.168.109.100
</code></pre> 
<pre><code class="prism language-powershell"><span class="token comment"># 创建 pv</span>
<span class="token namespace">[root@master ~]</span><span class="token comment"># kubectl create -f pv.yaml</span>
persistentvolume/pv1 created
persistentvolume/pv2 created
persistentvolume/pv3 created

<span class="token comment"># 查看pv</span>
<span class="token namespace">[root@master ~]</span><span class="token comment"># kubectl get pv -o wide</span>
NAME   CAPACITY   ACCESS MODES  RECLAIM POLICY  STATUS      AGE   VOLUMEMODE
pv1    1Gi        RWX            Retain        Available    10s   Filesystem
pv2    2Gi        RWX            Retain        Available    10s   Filesystem
pv3    3Gi        RWX            Retain        Available    9s    Filesystem
</code></pre> 
<h4><a id="PVC_402"></a>PVC</h4> 
<p>PVC是资源的申请，用来声明对存储空间、访问模式、存储类别需求信息。下面是资源清单文件:</p> 
<pre><code class="prism language-yaml"><span class="token key atrule">apiVersion</span><span class="token punctuation">:</span> v1
<span class="token key atrule">kind</span><span class="token punctuation">:</span> PersistentVolumeClaim
<span class="token key atrule">metadata</span><span class="token punctuation">:</span>
  <span class="token key atrule">name</span><span class="token punctuation">:</span> pvc
  <span class="token key atrule">namespace</span><span class="token punctuation">:</span> dev
<span class="token key atrule">spec</span><span class="token punctuation">:</span>
  <span class="token key atrule">accessModes</span><span class="token punctuation">:</span> <span class="token comment"># 访问模式</span>
  <span class="token key atrule">selector</span><span class="token punctuation">:</span> <span class="token comment"># 采用标签对PV选择</span>
  <span class="token key atrule">storageClassName</span><span class="token punctuation">:</span> <span class="token comment"># 存储类别</span>
  <span class="token key atrule">resources</span><span class="token punctuation">:</span> <span class="token comment"># 请求空间</span>
    <span class="token key atrule">requests</span><span class="token punctuation">:</span>
      <span class="token key atrule">storage</span><span class="token punctuation">:</span> 5Gi
</code></pre> 
<p>PVC 的关键配置参数说明：</p> 
<ul><li><strong>访问模式（accessModes）</strong></li></ul> 
<p>​ 用于描述用户应用对存储资源的访问权限</p> 
<ul><li> <p><strong>选择条件（selector）</strong></p> <p>通过Label Selector的设置，可使PVC对于系统中己存在的PV进行筛选</p> </li><li> <p><strong>存储类别（storageClassName）</strong></p> <p>PVC在定义时可以设定需要的后端存储的类别，只有设置了该class的pv才能被系统选出</p> </li><li> <p><strong>资源请求（Resources ）</strong></p> <p>描述对存储资源的请求</p> </li></ul> 
<p><strong>实验</strong></p> 
<ol><li>创建pvc.yaml，申请pv</li></ol> 
<pre><code class="prism language-yaml"><span class="token key atrule">apiVersion</span><span class="token punctuation">:</span> v1
<span class="token key atrule">kind</span><span class="token punctuation">:</span> PersistentVolumeClaim
<span class="token key atrule">metadata</span><span class="token punctuation">:</span>
  <span class="token key atrule">name</span><span class="token punctuation">:</span> pvc1
  <span class="token key atrule">namespace</span><span class="token punctuation">:</span> dev
<span class="token key atrule">spec</span><span class="token punctuation">:</span>
  <span class="token key atrule">accessModes</span><span class="token punctuation">:</span> 
  <span class="token punctuation">-</span> ReadWriteMany
  <span class="token key atrule">resources</span><span class="token punctuation">:</span>
    <span class="token key atrule">requests</span><span class="token punctuation">:</span>
      <span class="token key atrule">storage</span><span class="token punctuation">:</span> 1Gi
      
<span class="token punctuation">---</span>

<span class="token key atrule">apiVersion</span><span class="token punctuation">:</span> v1
<span class="token key atrule">kind</span><span class="token punctuation">:</span> PersistentVolumeClaim
<span class="token key atrule">metadata</span><span class="token punctuation">:</span>
  <span class="token key atrule">name</span><span class="token punctuation">:</span> pvc2
  <span class="token key atrule">namespace</span><span class="token punctuation">:</span> dev
<span class="token key atrule">spec</span><span class="token punctuation">:</span>
  <span class="token key atrule">accessModes</span><span class="token punctuation">:</span> 
  <span class="token punctuation">-</span> ReadWriteMany
  <span class="token key atrule">resources</span><span class="token punctuation">:</span>
    <span class="token key atrule">requests</span><span class="token punctuation">:</span>
      <span class="token key atrule">storage</span><span class="token punctuation">:</span> 1Gi
     
<span class="token punctuation">---</span>

<span class="token key atrule">apiVersion</span><span class="token punctuation">:</span> v1
<span class="token key atrule">kind</span><span class="token punctuation">:</span> PersistentVolumeClaim
<span class="token key atrule">metadata</span><span class="token punctuation">:</span>
  <span class="token key atrule">name</span><span class="token punctuation">:</span> pvc3
  <span class="token key atrule">namespace</span><span class="token punctuation">:</span> dev
<span class="token key atrule">spec</span><span class="token punctuation">:</span>
  <span class="token key atrule">accessModes</span><span class="token punctuation">:</span> 
  <span class="token punctuation">-</span> ReadWriteMany
  <span class="token key atrule">resources</span><span class="token punctuation">:</span>
    <span class="token key atrule">requests</span><span class="token punctuation">:</span>
      <span class="token key atrule">storage</span><span class="token punctuation">:</span> 1Gi
</code></pre> 
<pre><code class="prism language-powershell"><span class="token comment"># 创建pvc</span>
<span class="token namespace">[root@master ~]</span><span class="token comment"># kubectl create -f pvc.yaml</span>
persistentvolumeclaim/pvc1 created
persistentvolumeclaim/pvc2 created
persistentvolumeclaim/pvc3 created

<span class="token comment"># 查看pvc</span>
<span class="token namespace">[root@master ~]</span><span class="token comment"># kubectl get pvc  -n dev -o wide</span>
NAME   STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE   VOLUMEMODE
pvc1   Bound    pv1      1Gi        RWX                           15s   Filesystem
pvc2   Bound    pv2      2Gi        RWX                           15s   Filesystem
pvc3   Bound    pv3      3Gi        RWX                           15s   Filesystem

<span class="token comment"># 查看pv</span>
<span class="token namespace">[root@master ~]</span><span class="token comment"># kubectl get pv -o wide</span>
NAME  CAPACITY ACCESS MODES  RECLAIM POLICY  STATUS    CLAIM       AGE     VOLUMEMODE
pv1    1Gi        RWx        Retain          Bound    dev/pvc1    3h37m    Filesystem
pv2    2Gi        RWX        Retain          Bound    dev/pvc2    3h37m    Filesystem
pv3    3Gi        RWX        Retain          Bound    dev/pvc3    3h37m    Filesystem   
</code></pre> 
<ol start="2"><li>创建pods.yaml, 使用pv</li></ol> 
<pre><code class="prism language-yaml"><span class="token key atrule">apiVersion</span><span class="token punctuation">:</span> v1
<span class="token key atrule">kind</span><span class="token punctuation">:</span> Pod
<span class="token key atrule">metadata</span><span class="token punctuation">:</span>
  <span class="token key atrule">name</span><span class="token punctuation">:</span> pod1
  <span class="token key atrule">namespace</span><span class="token punctuation">:</span> dev
<span class="token key atrule">spec</span><span class="token punctuation">:</span>
  <span class="token key atrule">containers</span><span class="token punctuation">:</span>
  <span class="token punctuation">-</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> busybox
    <span class="token key atrule">image</span><span class="token punctuation">:</span> busybox<span class="token punctuation">:</span><span class="token number">1.30</span>
    <span class="token key atrule">command</span><span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">"/bin/sh"</span><span class="token punctuation">,</span><span class="token string">"-c"</span><span class="token punctuation">,</span><span class="token string">"while true;do echo pod1 &gt;&gt; /root/out.txt; sleep 10; done;"</span><span class="token punctuation">]</span>
    <span class="token key atrule">volumeMounts</span><span class="token punctuation">:</span>
    <span class="token punctuation">-</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> volume
      <span class="token key atrule">mountPath</span><span class="token punctuation">:</span> /root/
  <span class="token key atrule">volumes</span><span class="token punctuation">:</span>
    <span class="token punctuation">-</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> volume
      <span class="token key atrule">persistentVolumeClaim</span><span class="token punctuation">:</span>
        <span class="token key atrule">claimName</span><span class="token punctuation">:</span> pvc1
        <span class="token key atrule">readOnly</span><span class="token punctuation">:</span> <span class="token boolean important">false</span>
<span class="token punctuation">---</span>
<span class="token key atrule">apiVersion</span><span class="token punctuation">:</span> v1
<span class="token key atrule">kind</span><span class="token punctuation">:</span> Pod
<span class="token key atrule">metadata</span><span class="token punctuation">:</span>
  <span class="token key atrule">name</span><span class="token punctuation">:</span> pod2
  <span class="token key atrule">namespace</span><span class="token punctuation">:</span> dev
<span class="token key atrule">spec</span><span class="token punctuation">:</span>
  <span class="token key atrule">containers</span><span class="token punctuation">:</span>
  <span class="token punctuation">-</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> busybox
    <span class="token key atrule">image</span><span class="token punctuation">:</span> busybox<span class="token punctuation">:</span><span class="token number">1.30</span>
    <span class="token key atrule">command</span><span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">"/bin/sh"</span><span class="token punctuation">,</span><span class="token string">"-c"</span><span class="token punctuation">,</span><span class="token string">"while true;do echo pod2 &gt;&gt; /root/out.txt; sleep 10; done;"</span><span class="token punctuation">]</span>
    <span class="token key atrule">volumeMounts</span><span class="token punctuation">:</span>
    <span class="token punctuation">-</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> volume
      <span class="token key atrule">mountPath</span><span class="token punctuation">:</span> /root/
  <span class="token key atrule">volumes</span><span class="token punctuation">:</span>
    <span class="token punctuation">-</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> volume
      <span class="token key atrule">persistentVolumeClaim</span><span class="token punctuation">:</span>
        <span class="token key atrule">claimName</span><span class="token punctuation">:</span> pvc2
        <span class="token key atrule">readOnly</span><span class="token punctuation">:</span> <span class="token boolean important">false</span>        
</code></pre> 
<pre><code class="prism language-powershell"><span class="token comment"># 创建pod</span>
<span class="token namespace">[root@master ~]</span><span class="token comment"># kubectl create -f pods.yaml</span>
pod/pod1 created
pod/pod2 created

<span class="token comment"># 查看pod</span>
<span class="token namespace">[root@master ~]</span><span class="token comment"># kubectl get pods -n dev -o wide</span>
NAME   READY   STATUS    RESTARTS   AGE   IP            NODE   
pod1   1/1     Running   0          14s   10<span class="token punctuation">.</span>244<span class="token punctuation">.</span>1<span class="token punctuation">.</span>69   node1   
pod2   1/1     Running   0          14s   10<span class="token punctuation">.</span>244<span class="token punctuation">.</span>1<span class="token punctuation">.</span>70   node1  

<span class="token comment"># 查看pvc</span>
<span class="token namespace">[root@master ~]</span><span class="token comment"># kubectl get pvc -n dev -o wide</span>
NAME   STATUS   VOLUME   CAPACITY   ACCESS MODES      AGE   VOLUMEMODE
pvc1   Bound    pv1      1Gi        RWX               94m   Filesystem
pvc2   Bound    pv2      2Gi        RWX               94m   Filesystem
pvc3   Bound    pv3      3Gi        RWX               94m   Filesystem

<span class="token comment"># 查看pv</span>
<span class="token namespace">[root@master ~]</span><span class="token comment"># kubectl get pv -n dev -o wide</span>
NAME   CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM       AGE     VOLUMEMODE
pv1    1Gi        RWX            Retain           Bound    dev/pvc1    5h11m   Filesystem
pv2    2Gi        RWX            Retain           Bound    dev/pvc2    5h11m   Filesystem
pv3    3Gi        RWX            Retain           Bound    dev/pvc3    5h11m   Filesystem

<span class="token comment"># 查看nfs中的文件存储</span>
<span class="token namespace">[root@master ~]</span><span class="token comment"># more /root/data/pv1/out.txt</span>
node1
node1
<span class="token namespace">[root@master ~]</span><span class="token comment"># more /root/data/pv2/out.txt</span>
node2
node2
</code></pre> 
<h4><a id="subPath_584"></a>subPath</h4> 
<p>现在是不是正常了啊，但是我们可以看到我们容器中的数据是直接放到共享数据目录根目录下面的，如果以后我们又有一个新的 nginx 容器也做了数据目录的挂载，是不是就会有冲突了啊，所以这个时候就不太好区分了，这个时候我们可以在 Pod 中使用一个新的属性：subPath，该属性可以来解决这个问题，我们只需要更改上面的 Pod 的 YAML 文件即可：</p> 
<pre><code>...
volumeMounts:
- name: www
  subPath: nginxpvc-test
  mountPath: /usr/share/nginx/html
...
</code></pre> 
<p>更新完后，我们再去看看 nfs 的数据共享目录：</p> 
<pre><code>$ ls /root/data/
index.html  nginxpvc-test
$ ls /data/k8s/nginxpvc-test/
</code></pre> 
<h4><a id="_601"></a>生命周期</h4> 
<p>PVC和PV是一一对应的，PV和PVC之间的相互作用遵循以下生命周期：</p> 
<ul><li> <p><strong>资源供应</strong>：管理员手动创建底层存储和PV</p> </li><li> <p><strong>资源绑定</strong>：用户创建PVC，kubernetes负责根据PVC的声明去寻找PV，并绑定</p> <p>在用户定义好PVC之后，系统将根据PVC对存储资源的请求在已存在的PV中选择一个满足条件的</p> 
  <ul><li> <p>一旦找到，就将该PV与用户定义的PVC进行绑定，用户的应用就可以使用这个PVC了</p> </li><li> <p>如果找不到，PVC则会无限期处于Pending状态，直到等到系统管理员创建了一个符合其要求的PV</p> </li></ul> <p>PV一旦绑定到某个PVC上，就会被这个PVC独占，不能再与其他PVC进行绑定了</p> </li><li> <p><strong>资源使用</strong>：用户可在pod中像volume一样使用pvc</p> <p>Pod使用Volume的定义，将PVC挂载到容器内的某个路径进行使用。</p> </li><li> <p><strong>资源释放</strong>：用户删除pvc来释放pv</p> <p>当存储资源使用完毕后，用户可以删除PVC，与该PVC绑定的PV将会被标记为“已释放”，但还不能立刻与其他PVC进行绑定。通过之前PVC写入的数据可能还被留在存储设备上，只有在清除之后该PV才能再次使用。</p> </li><li> <p><strong>资源回收</strong>：kubernetes根据pv设置的回收策略进行资源的回收</p> <p>对于PV，管理员可以设定回收策略，用于设置与之绑定的PVC释放资源之后如何处理遗留数据的问题。只有PV的存储空间完成回收，才能供新的PVC绑定和使用</p> </li></ul> 
<p><img src="https://i-blog.csdnimg.cn/blog_migrate/7634dded4f178c43417114f73d9efb95.png" alt=""></p> 
<h3><a id="_631"></a>配置存储</h3> 
<h4><a id="ConfigMap_633"></a>ConfigMap</h4> 
<p>ConfigMap是一种比较特殊的存储卷，它的主要作用是用来存储配置信息的。</p> 
<p>创建configmap.yaml，内容如下：</p> 
<pre><code class="prism language-yaml"><span class="token key atrule">apiVersion</span><span class="token punctuation">:</span> v1
<span class="token key atrule">kind</span><span class="token punctuation">:</span> ConfigMap
<span class="token key atrule">metadata</span><span class="token punctuation">:</span>
  <span class="token key atrule">name</span><span class="token punctuation">:</span> configmap
  <span class="token key atrule">namespace</span><span class="token punctuation">:</span> dev
<span class="token key atrule">data</span><span class="token punctuation">:</span>
  <span class="token key atrule">data.1</span><span class="token punctuation">:</span> hello
  <span class="token key atrule">data.2</span><span class="token punctuation">:</span> world
  <span class="token key atrule">info</span><span class="token punctuation">:</span> <span class="token punctuation">|</span><span class="token scalar string">
    username:admin
    password:123456</span>
</code></pre> 
<p>当然同样的我们可以使用kubectl create -f xx.yaml来创建上面的ConfigMap对象，但是如果我们不知道怎么创建ConfigMap的话，不要忘记kubectl是我们最好的老师，可以使用kubectl create configmap -h来查看关于创建ConfigMap的帮助信息，<br> 接下来，使用此配置文件创建configmap</p> 
<pre><code>Examples:
  # Create a new configmap named my-config based on folder bar
  kubectl create configmap my-config --from-file=path/to/bar

  # Create a new configmap named my-config with specified keys instead of file basenames on disk
  kubectl create configmap my-config --from-file=key1=/path/to/bar/file1.txt --from-file=key2=/path/to/bar/file2.txt

  # Create a new configmap named my-config with key1=config1 and key2=config2
  kubectl create configmap my-config --from-literal=key1=config1 --from-literal=key2=config2
</code></pre> 
<pre><code class="prism language-powershell"><span class="token comment"># 创建configmap</span>
<span class="token namespace">[root@master ~]</span><span class="token comment"># kubectl create -f configmap.yaml</span>
configmap/configmap created

<span class="token comment"># 查看configmap详情</span>
<span class="token namespace">[root@master ~]</span><span class="token comment"># kubectl describe cm configmap -n dev</span>
Name:         configmap
Namespace:    dev
Labels:       &lt;none&gt;
Annotations:  &lt;none&gt;

<span class="token keyword">Data</span>
====
info:
<span class="token operator">--</span><span class="token operator">--</span>
username:admin
password:123456

Events:  &lt;none&gt;
</code></pre> 
<p>接下来创建一个pod-configmap.yaml，将上面创建的configmap挂载进去</p> 
<pre><code class="prism language-yaml"><span class="token key atrule">apiVersion</span><span class="token punctuation">:</span> v1
<span class="token key atrule">kind</span><span class="token punctuation">:</span> Pod
<span class="token key atrule">metadata</span><span class="token punctuation">:</span>
  <span class="token key atrule">name</span><span class="token punctuation">:</span> pod<span class="token punctuation">-</span>configmap
  <span class="token key atrule">namespace</span><span class="token punctuation">:</span> dev
<span class="token key atrule">spec</span><span class="token punctuation">:</span>
  <span class="token key atrule">containers</span><span class="token punctuation">:</span>
  <span class="token punctuation">-</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> nginx
    <span class="token key atrule">image</span><span class="token punctuation">:</span> nginx<span class="token punctuation">:</span>1.17.1
    <span class="token key atrule">volumeMounts</span><span class="token punctuation">:</span> <span class="token comment"># 将configmap挂载到目录</span>
    <span class="token punctuation">-</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> config
      <span class="token key atrule">mountPath</span><span class="token punctuation">:</span> /configmap/config
  <span class="token key atrule">volumes</span><span class="token punctuation">:</span> <span class="token comment"># 引用configmap</span>
  <span class="token punctuation">-</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> config
    <span class="token key atrule">configMap</span><span class="token punctuation">:</span>
      <span class="token key atrule">name</span><span class="token punctuation">:</span> configmap
</code></pre> 
<pre><code class="prism language-powershell"><span class="token comment"># 创建pod</span>
<span class="token namespace">[root@master ~]</span><span class="token comment"># kubectl create -f pod-configmap.yaml</span>
pod/pod-configmap created

<span class="token comment"># 查看pod</span>
<span class="token namespace">[root@master ~]</span><span class="token comment"># kubectl get pod pod-configmap -n dev</span>
NAME            READY   STATUS    RESTARTS   AGE
pod-configmap   1/1     Running   0          6s

<span class="token comment">#进入容器</span>
<span class="token namespace">[root@master ~]</span><span class="token comment"># kubectl exec -it pod-configmap -n dev /bin/sh</span>
<span class="token comment"># cd /configmap/config/</span>
<span class="token comment"># ls</span>
info
<span class="token comment"># more info</span>
username:admin
password:123456

<span class="token comment"># 可以看到映射已经成功，每个configmap都映射成了一个目录</span>
<span class="token comment"># key---&gt;文件     value----&gt;文件中的内容</span>
<span class="token comment"># 此时如果更新configmap的内容, 容器中的值也会动态更新</span>
</code></pre> 
<h4><a id="Secret_733"></a>Secret</h4> 
<p>上面学习了ConfigMap的时候，我们说ConfigMap这个资源对象是Kubernetes当中非常重要的一个对象，一般情况下ConfigMap是用来存储一些非安全的配置信息，如果涉及到一些安全相关的数据的话用ConfigMap就非常不妥了，因为ConfigMap是名为存储的，我们说这个时候我们就需要用到另外一个资源对象了：Secret，Secret用来保存敏感信息，例如密码、OAuth 令牌和 ssh key等等，将这些信息放在Secret中比放在Pod的定义中或者docker镜像中来说更加安全和灵活。</p> 
<p>Secret有三种类型：</p> 
<ul><li>Opaque：base64 编码格式的 Secret，用来存储密码、密钥等；但数据也可以通过base64 –decode解码得到原始数据，所有加密性很弱。</li><li>kubernetes.io/dockerconfigjson：用来存储私有docker registry的认证信息。</li><li>kubernetes.io/service-account-token：用于被serviceaccount引用，serviceaccout 创建时Kubernetes会默认创建对应的secret。Pod如果使用了serviceaccount，对应的secret会自动挂载到Pod目录/run/secrets/kubernetes.io/serviceaccount中。<br> ​</li></ul> 
<h5><a id="Opaque_Secret_742"></a>Opaque Secret</h5> 
<p>Opaque 类型的数据是一个 map 类型，要求value是base64编码格式，比如我们来创建一个用户名为 admin，密码为 admin321 的 Secret 对象，首先我们先把这用户名和密码做 base64 编码，</p> 
<ol><li>首先使用base64对数据进行编码</li></ol> 
<pre><code class="prism language-yaml"><span class="token punctuation">[</span>root@master ~<span class="token punctuation">]</span><span class="token comment"># echo -n 'admin' | base64 #准备username</span>
YWRtaW4=
<span class="token punctuation">[</span>root@master ~<span class="token punctuation">]</span><span class="token comment"># echo -n '123456' | base64 #准备password</span>
MTIzNDU2
</code></pre> 
<ol start="2"><li>接下来编写secret.yaml，并创建Secret</li></ol> 
<pre><code class="prism language-yaml"><span class="token key atrule">apiVersion</span><span class="token punctuation">:</span> v1
<span class="token key atrule">kind</span><span class="token punctuation">:</span> Secret
<span class="token key atrule">metadata</span><span class="token punctuation">:</span>
  <span class="token key atrule">name</span><span class="token punctuation">:</span> secret
  <span class="token key atrule">namespace</span><span class="token punctuation">:</span> dev
<span class="token key atrule">type</span><span class="token punctuation">:</span> Opaque
<span class="token key atrule">data</span><span class="token punctuation">:</span>
  <span class="token key atrule">username</span><span class="token punctuation">:</span> YWRtaW4=
  <span class="token key atrule">password</span><span class="token punctuation">:</span> MTIzNDU2
</code></pre> 
<pre><code class="prism language-powershell"><span class="token comment"># 创建secret</span>
<span class="token namespace">[root@master ~]</span><span class="token comment"># kubectl create -f secret.yaml</span>
secret/secret created

<span class="token comment"># 查看secret详情</span>
<span class="token namespace">[root@master ~]</span><span class="token comment"># kubectl describe secret secret -n dev</span>
Name:         secret
Namespace:    dev
Labels:       &lt;none&gt;
Annotations:  &lt;none&gt;
<span class="token function">Type</span>:  Opaque
<span class="token keyword">Data</span>
====
password:  6 bytes
username:  5 bytes
</code></pre> 
<ol start="3"><li>创建好Secret对象后，有两种方式来使用它：</li></ol> 
<ul><li>以环境变量的形式</li><li>以Volume的形式挂载</li></ul> 
<h6><a id="_788"></a>环境变量</h6> 
<p>首先我们来测试下环境变量的方式，同样的，我们来使用一个简单的busybox镜像来测试下:(secret1-pod.yaml)</p> 
<pre><code>apiVersion: v1
kind: Pod
metadata:
  name: secret1-pod
spec:
  containers:
  - name: secret1
    image: busybox
    command: [ "/bin/sh", "-c", "env" ]
    env:
    - name: USERNAME
      valueFrom:
        secretKeyRef:
          name: mysecret
          key: username
    - name: PASSWORD
      valueFrom:
        secretKeyRef:
          name: mysecret
          key: password
</code></pre> 
<p>主要上面环境变量中定义的secretKeyRef关键字，和我们上面的configMapKeyRef是不是比较类似，一个是从Secret对象中获取，一个是从ConfigMap对象中获取，创建上面的Pod：</p> 
<pre><code>$ kubectl create -f secret1-pod.yaml
pod "secret1-pod" created
</code></pre> 
<p>然后我们查看Pod的日志输出：</p> 
<pre><code>$ kubectl logs secret1-pod
...
USERNAME=admin
PASSWORD=123456
...
</code></pre> 
<h6><a id="Volume__825"></a>Volume 挂载</h6> 
<p>同样的我们用一个Pod来验证下Volume挂载，创建一个Pod文件：(secret2-pod.yaml)</p> 
<pre><code>apiVersion: v1
kind: Pod
metadata:
  name: secret2-pod
spec:
  containers:
  - name: secret2
    image: busybox
    command: ["/bin/sh", "-c", "ls /etc/secrets"]
    volumeMounts:
    - name: secrets
      mountPath: /etc/secrets
  volumes:
  - name: secrets
    secret:
     secretName: mysecret
</code></pre> 
<p>创建Pod:</p> 
<pre><code>$ kubectl create -f secret-pod2.yaml
pod "secret2-pod" created
</code></pre> 
<p>然后我们查看输出日志：</p> 
<pre><code>$ kubectl logs secret2-pod
password
username
</code></pre> 
<p>可以看到secret把两个key挂载成了两个对应的文件。当然如果想要挂载到指定的文件上面，是不是也可以使用上一节课的方法：在secretName下面添加items指定 key 和 path，这个大家可以参考上节课ConfigMap中的方法去测试下。</p> 
<p>至此，已经实现了利用secret实现了信息的编码,其他两种不常用，就不展示了。</p> 
<h5><a id="_kubectl__Secret_861"></a>使用 kubectl 管理 Secret</h5> 
<pre><code>kubectl create secret generic db-user-pass \
    --from-literal=username=devuser \
    --from-literal=password='S!B\*d$zDsb='
</code></pre> 
<p>使用源文件</p> 
<pre><code>kubectl create secret generic db-user-pass \
    --from-file=./username.txt \
    --from-file=./password.txt
</code></pre> 
<h4><a id="Secret__ConfigMap__876"></a>Secret 与 ConfigMap 对比</h4> 
<p>最后我们来对比下Secret和ConfigMap这两种资源对象的异同点：</p> 
<p>相同点：</p> 
<ul><li> <p>key/value的形式</p> </li><li> <p>属于某个特定的namespace</p> </li><li> <p>可以导出到环境变量</p> </li><li> <p>可以通过目录/文件形式挂载</p> </li><li> <p>通过 volume 挂载的配置信息均可热更新<br> 不同点：</p> </li><li> <p>Secret 可以被 ServerAccount 关联</p> </li><li> <p>Secret 可以存储 docker register 的鉴权信息，用在 ImagePullSecret 参数中，用于拉取私有仓库的镜像</p> </li><li> <p>Secret 支持 Base64 加密</p> </li><li> <p>Secret 分为 kubernetes.io/service-account-token、kubernetes.io/dockerconfigjson、Opaque 三种类型，而 Configmap 不区分类型</p> </li></ul> 
<h2><a id="nacos_config_892"></a>nacos config实战</h2> 
<pre><code>###使用自建数据库；使用Ingress发布配置后台###
apiVersion: v1
kind: Service
metadata:
  name: nacos-headless
  labels:
    app: nacos-headless
spec:
  type: ClusterIP
  clusterIP: None
  ports:
    - port: 8848
      name: server
      targetPort: 8848
    - port: 9848
      name: client-rpc
      targetPort: 9848
    - port: 9849
      name: raft-rpc
      targetPort: 9849
  selector:
    app: nacos
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: nacos-cm
data:
  mysql.host: '192.168.0.9'
  mysql.db.name: 'nacos_config'
  mysql.port: '3306'
  mysql.user: 'nacos'
  mysql.password: '123456'
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: nacos
spec:
  serviceName: nacos-headless
  replicas: 3
  template:
    metadata:
      labels:
        app: nacos
      annotations:
        pod.alpha.kubernetes.io/initialized: 'true'
    spec:
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            - labelSelector:
                matchExpressions:
                  - key: 'app'
                    operator: In
                    values:
                      - nacos
              topologyKey: 'kubernetes.io/hostname'
      containers:
        - name: k8snacos
          imagePullPolicy: IfNotPresent
          image: nacos/nacos-server:v2.0.3
          resources:
            requests:
              memory: '1Gi'
              cpu: '500m'
          ports:
            - containerPort: 8848
              name: client
            - containerPort: 9848
              name: client-rpc
            - containerPort: 9849
              name: raft-rpc
            - containerPort: 7848
              name: old-raft-rpc
          env:
            - name: NACOS_REPLICAS
              value: '3'
            - name: MYSQL_SERVICE_HOST
              valueFrom:
                configMapKeyRef:
                  name: nacos-cm
                  key: mysql.host
            - name: MYSQL_SERVICE_DB_NAME
              valueFrom:
                configMapKeyRef:
                  name: nacos-cm
                  key: mysql.db.name
            - name: MYSQL_SERVICE_PORT
              valueFrom:
                configMapKeyRef:
                  name: nacos-cm
                  key: mysql.port
            - name: MYSQL_SERVICE_USER
              valueFrom:
                configMapKeyRef:
                  name: nacos-cm
                  key: mysql.user
            - name: MYSQL_SERVICE_PASSWORD
              valueFrom:
                configMapKeyRef:
                  name: nacos-cm
                  key: mysql.password
            - name: MODE
              value: 'cluster'
            - name: NACOS_SERVER_PORT
              value: '8848'
            - name: PREFER_HOST_MODE
              value: 'hostname'
            - name: NACOS_SERVERS
              value: 'nacos-0.nacos-headless.cloud.svc.cluster.local:8848 nacos-1.nacos-headless.cloud.svc.cluster.local:8848 nacos-2.nacos-headless.cloud.svc.cluster.local:8848'
  selector:
    matchLabels:
      app: nacos

---
# ------------------- App Ingress ------------------- #
kind: Ingress
apiVersion: networking.k8s.io/v1
metadata:
  name: nacos-headless
  annotations:
    kubernetes.io/ingress.class: nginx
spec:
  rules:
    - host: nacos.bcqqq.com1
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: nacos-headless
                port:
                  number: 8848

</code></pre>
                </div>
            </body>
            </html>
            